#pragma once
#include <vector>
#include <string>
#include <tuple>

#include "stringer.h"
#include "box.h"
#include "rivet.h"


class position {
public:
	position(double x, double y, double z, int orientation = 1, int index = 0) 
	{
		this->x = (x);
		this->y = (y);
		this->z = (z);
		this->orientation = orientation;
		this->index = index;
	}
	double x;
	double y;
	double z;
	int orientation;
	int index;
};


class wingbox : public baseobject {
public:

	typedef std::tuple<stringer, position, std::vector<double> > stringerdata;
	typedef std::vector<stringerdata> stringerlist;
	typedef stringerlist::iterator stringer_iterator;
	typedef stringerlist::const_iterator stringer_const_iterator;
	typedef std::vector<int> removeorder_list;
	typedef std::vector<removeorder_list> permutation_list;
	typedef std::vector<std::pair<stringer_const_iterator, double> > FailSeqSheetListTy;

	typedef std::vector<std::pair<stringer_const_iterator, std::vector<std::pair<int,  double> > > > FailSeqIRListTy;

	wingbox (int number_stringers, const stringer& _s, const box& _b, const rivet& _r, double rib1pos, double rib2pos, double loadbuckling, double loadfail, double safety = 1);
	wingbox (int number_stringers, const stringer& _s, const box& _b, const rivet& _r, double rib1pos, double rib2pos, double loadbuckling, double loadfail, double safety_stringer, double safety_rivets);

	virtual double inertia() const;
	virtual double centroid() const;
	virtual double weight() const;
	virtual double area() const;
	virtual double inertia(double p) const;
	virtual double centroid(double p) const;
	virtual double area(double p) const;

	bool setStringerSpacings(const std::vector<double>& spacings);

	virtual void displaydata() const;
	void displaystringerdata() const;

	int numberTopStringers() const;

	double& getSafetyStringers();
	const double& getSafetyStringers() const;
	double& getSafetyRivets();
	const double& getSafetyRivets() const;

	void changeMaterial(const material& m);
	void changeBox(double w, double h, double t, double l, double s);
	void changeStringer(int n, double w, double t);
	void changeRibPositions(double rib1, double rib2);
	void changeSafetyFactors(double stringers, double rivets);
	void changeMaximumLoadings(double buckling_load, double ultimate_load);
	void changeBucklingConstants(double Kc, double endfixity);
	void changeClamps(double clamp_root, double clamp_tip);
	void changeName(const std::string& newname);


	void saveBox(const std::string& filename) const;
	void saveCommon(std::ostream& file) const;
	void saveStringers(std::ostream& file) const;
	void saveRivets(std::ostream& file) const;
	void saveFailure(std::ostream& file, const FailSeqIRListTy& faillist, 
		const FailSeqSheetListTy& TopSheet, const FailSeqSheetListTy& TopSheetRoot, 
		const std::pair<stringer_const_iterator, double>& failure) const;
	void saveFailureIR(std::ostream& file, const FailSeqIRListTy& faillist) const;
	void saveFailureSheet(std::ostream& file, const FailSeqSheetListTy& TopSheet, const FailSeqSheetListTy& TopSheetRoot) const;
	void saveFailureBot(std::ostream& file, const std::pair<stringer_const_iterator, double>& failure) const;

	void findBestRemovalOrder();

	double minimum_spacing;
	std::pair<int, double> maximum_spacing(double pos) const;
	double maximum_spacing_sheet_buckling(double pos) const;
	double maximum_spacing_column_buckling(double pos) const;

	double findSpacingPossible(double spacing, double moment_of_inertia, double centroid_, double kc) const;
	double findSpacingPossibleNoSweep(double spacing, double moment_of_inertia, double centroid_, double kc) const;

	void createRivets();


		//failure
	FailSeqIRListTy FailureSequenceIR() const;
	FailSeqSheetListTy FailureSequenceSheet() const;
	FailSeqSheetListTy FailureSequenceSheetAtRoot() const;
	std::pair<wingbox::stringer_const_iterator, double> FailureSequenceBottom() const;

private:
	box b;
	double rib1;
	double rib2;
	double bucklingload;
	double failureload;
	double safetyfactorstringers;
	double safetyfactorrivets;

	void createTopStringers(const stringer& _s);
	void createBotStringers(const stringer& _s);




	stringerlist top_stringers;
	stringerlist bottom_stringers;
	
	void cutTopStringers();
	void cutBotStringers();
	void cutStringers();
	void cutStringers(stringer_iterator b, stringer_iterator e);
	void cutStringer(stringerdata& sdata);

	double getKc(double pos) const;
	double getSweepFactor(double pos) const;

	double centroidBotStringers() const;
	double areaBotStringers() const;
	double weightBotStringers() const;
	double centroidTopStringers() const;
	double areaTopStringers() const;
	double weightTopStringers() const;
	double areaStringers(stringer_const_iterator b, stringer_const_iterator e) const;
	double centroidStringers(const stringerlist::value_type& sdata) const;
	double weightStringers(stringer_const_iterator b, stringer_const_iterator e) const;

	double inertiaBotStringers() const;
	double inertiaTopStringers() const;
	double inertiaStringers(stringer_const_iterator b, stringer_const_iterator e) const;
	
	double testRemovalOrder(const removeorder_list& permutation);


	double areaBotStringers(double pos) const;
	double areaTopStringers(double pos) const;
	double areaStringers(stringer_const_iterator b, stringer_const_iterator e, double pos) const;

	double inertiaBotStringers(double pos) const;
	double inertiaTopStringers(double pos) const;
	double inertiaStringers(stringer_const_iterator b, stringer_const_iterator e, double pos) const;

	static bool stringerAtPos(const stringerlist::value_type& sdata, double pos);

	permutation_list unique_permutations;
	void createPermutations();
	double calcSpaceWithout(wingbox::stringer_const_iterator i, double pos) const ;
	double calcSpace(double xpos, double ypos);


	//rivets
	rivet poprivets;
	

	double getRivetEndFixity(double pos) const;

	void addRivets(const stringer& s, const position& p, std::vector<double>& rivets);
	double nextRivet(double x) const;
	int numberTotalRivets() const;
	int numberTotalRivets(const stringerdata& sdata) const;
	double weightRivets() const;



	double FailureSequenceIR(double pos, double spacing) const;
	double FailureSequenceSheet(double pos, double spacing) const;
	double FailureSequenceBottom(double pos) const;

};